#include "CPlane.h"



 
CPlane::CPlane( const fixed* abcd )
{ 
	ASSERT( abcd );

	m_n = *abcd;
	m_d = *( abcd + 3 );
}


CPlane::CPlane( const CVector3d& v0, const CVector3d& v1, const CVector3d& v2 )
{
	m_n = v1 - v0;
	m_n.Cross( v2 - v0 );
	m_n.Normalize();
	m_d = v0 * m_n;
}


CPlane& CPlane::Set( const CVector3d& v0, const CVector3d& v1, const CVector3d& v2 )
{
	m_n = v1 - v0;
	m_n.Cross( v2 - v0 );
	m_n.Normalize();
	m_d = v0 * m_n;

	return *this;
}


CPlane::AxisAlignedPlane CPlane::GetClosestAxisAlignedPlane( const CVector3d& normal )
{
	fixed jk = CMathFixed::Abs( normal.m_i );
	fixed ik = CMathFixed::Abs( normal.m_j );
	fixed ij = CMathFixed::Abs( normal.m_k );

	ASSERT ( ( ij != 0 && jk != 0 && ik != 0 ) );

	if ( ij >= jk && ij >= ik )
		return IJ;
	else if ( jk >= ik )
		return JK;
	else return KI;
}


CPlane& CPlane::Normalize()
{
	fixed len = m_n.Length();

	if( len )
	{
		*this /= len;

		m_d = CMathFixed::Div( m_d, len );
	}

	return *this;
}


CSpace::Relativity CPlane::DetermineSpace( fixed signedDistanceToPoint ) const
{
	if( signedDistanceToPoint < 0 )
		return CSpace::Outside;
	else
	if( signedDistanceToPoint > 0 )
		return CSpace::Inside;
	else
		return CSpace::Intersecting;
}


boolean	CPlane::Intersects( const CVector3d& v0, const CVector3d& v1, CVector3d& outPoint, fixed& u ) const
{
	CVector3d v0v1 = v1 - v0;
	fixed nDotVoV1 = m_n * v0v1;

	if( CMathFixed::Abs( nDotVoV1 ) <= CMathFixed_FloatToFixed( 0.001f ) /*EPSILON*/)
	{
		u = CMathFixed::Div( m_d - m_n * v0, nDotVoV1 );

		if( u >= 0 && u <= CMathFixed::One )
		{
			outPoint = v0 + u * v0v1;
			return TRUE;
		}
	}

	return FALSE;
}


boolean CPlane::Intersects( const CPlane& p, CVector3d& lineNormal ) const
{
	lineNormal = m_n;

	lineNormal.Cross( p.m_n );

	if( lineNormal * lineNormal < 0 )
		return FALSE;
	else
		return TRUE;
}


boolean CPlane::Intersects( const CPlane& p, CVector3d& lineNormal, CVector3d& pt ) const
{
	lineNormal = m_n;
	lineNormal.Cross( p.m_n );
	fixed d = lineNormal * lineNormal;

	if ( d < CMathFixed_FloatToFixed( 0.0001f ) /* EPSILON */ )
		return FALSE;

	// compute point on intersection line

	pt = m_d * p.m_n - p.m_d * m_n;
	pt.Cross( lineNormal );
	// pt /= d; // optional needed only when normals are not normalized

	return TRUE;

}


boolean CPlane::Intersects( const CPlane& p1, const CPlane& p2, CVector3d& pt ) const
{
	const CPlane& p0 = *this;

	CVector3d u( p1.m_n );
	u.Cross( p2.m_n );

	fixed denom = p0.m_n * u;

	if ( CMathFixed::Abs( denom ) < CMathFixed_FloatToFixed( 0.001f ) /*EPSILON*/ )
		return FALSE;

	pt = p0.m_n;
	pt.Cross( p2.m_d * p1.m_n - p1.m_d * p2.m_n );
	pt += ( p0.m_d * u );
	pt /= denom;
	return TRUE;
}


CPlane& CPlane::operator=( const fixed* abcd )
{
	ASSERT( abcd );

	m_n = abcd;
	m_d = *( abcd + 3 );

	return *this;
}


CPlane& CPlane::operator+=( fixed val )
{
	m_n += val;
	m_d += val;

	return *this;
}


CPlane& CPlane::operator-=( fixed val )
{
	m_n -= val;
	m_d -= val;

	return *this;
}


CPlane& CPlane::operator*=( fixed val )
{
	m_n *= val;
	m_d = CMathFixed::Mul( m_d, val );

	return *this;
}


CPlane& CPlane::operator/=( fixed val )
{
	m_n /= val;
	m_d = CMathFixed::Div( m_d, val );

	return *this;
}

